Skip to content

iceoryx2 发布订阅上手:节点、服务与零拷贝收发 ​

本文翻译整理自 The iceoryx2 Book 的 Getting Started — A Robot Nervous System — Publish–Subscribe 一章,代码与叙述以官方文档为准。适合第一次接触 iceoryx2、想跑通第一个发布订阅示例的开发者;读完可以得到从创建节点到零拷贝收发消息的完整代码路径。iceoryx2 的分层架构与四种通信模型的概览,可以先阅读 book 的 concepts 章节。

一切从节点开始 ​

在 iceoryx2 中,一切皆以节点开始。节点代表一个通信点(如进程或线程),并充当服务的工厂。为了在调试时保持条理清晰,给这个节点命名:

cpp
#include "iceoryx2.hpp"

using namespace iox2;

auto node = NodeBuilder()
    .name(NodeName::create("UltraSonicSensor").value())
    .create<ServiceType::Ipc>().value();

定义负载结构体 ​

现在我们可以创建一个名为 "distance_to_obstacle" 的服务,使用 Distance 结构体作为有效载荷类型。有效载荷必须是共享内存兼容的,这意味着:

  • self contained,自包含的
  • no internal pointers,无内部指针
  • identical memory representation,相同的内存表示
cpp
struct Distance {
    double distance_in_meters;
    float some_other_property;
};

inline auto operator<<(std::ostream& stream, const Distance& value) -> std::ostream& {
    stream << "Distance { distance_in_meters: " << value.distance_in_meters
           << ", some_other_property: " << value.some_other_property << " }";
    return stream;
}

创建服务与发布者 ​

在定义了有效载荷后,我们可以设置该服务:

cpp
auto service = node.service_builder(ServiceName::create("distance_to_obstacle").value())
                   .publish_subscribe<Distance>()
                   .open_or_create()
                   .value();

现在我们创建我们的发布者:

cpp
auto publisher = service.publisher_builder().create().value();

要充分利用零拷贝,我们不分配或克隆数据。相反,我们从发布者的内存池中借一个未初始化的样本,填充它,然后以 100 ms 的间隔发送它:

cpp
while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
    auto sample = publisher.loan_uninit().value();

    auto initialized_sample =
      sample.write_payload(Distance { get_ultra_sonic_sensor_distance(), 42.0 });

    send(std::move(initialized_sample)).value();
}

创建订阅者 ​

创建订阅者与发布者类似:

cpp
#include "iox2/iceoryx2.hpp"

using namespace iox2;

auto node = NodeBuilder().create<ServiceType::Ipc>().value();

auto service = node.service_builder(ServiceName::create("distance_to_obstacle").value())
                   .publish_subscribe<Distance>()
                   .open_or_create()
                   .value();

auto subscriber = service.subscriber_builder().create().value();

while (node.wait(iox2::bb::Duration::from_millis(100)).has_value()) {
    auto sample = subscriber.receive().value();
    while (sample.has_value()) {
        std::cout << "received distance: " << sample->payload() << std::endl;
        sample = subscriber.receive().value();
    }
}

小结 ​

上手路径一共四步:NodeBuilder 建节点(进程内通信用 ServiceType::Ipc)→ 定义共享内存兼容的负载结构体 → service_builder(...).publish_subscribe<T>().open_or_create() 建服务 → publisher_builder() / subscriber_builder() 创建收发两端。发布侧的核心是 loan_uninit() 借样本、write_payload() 填充后发送的零拷贝流程,这也是 pub-sub 模型无论负载大小都能保持基本恒定延迟的原因。


译注:发布循环中的 send(std::move(initialized_sample)).value(); 来自官方示例的辅助封装,完整可编译代码见 iceoryx2 仓库的 examples/cxx/publish_subscribe 目录。本站相关文章:iceoryx2 黑板机制:共享内存配置分发、iceoryx2 动态类型:Slice 动态 payload 与多段扩容。

最近更新

基于 VitePress 构建